using SG3L_RAG.Application.Interfaces;
using SG3L_RAG.Application.DTOs;
using SG3L_RAG.Domain.Entities;
using SG3L_RAG.Domain.Repositories;

namespace SG3L_RAG.Application.Services
{
    public class VectorSearchService : IVectorSearchService
    {
        private readonly IRepository<DocumentChunk> _chunkRepository;
        private readonly IRepository<Document> _documentRepository;
        private readonly IAIService _aiService;

        public VectorSearchService(
            IRepository<DocumentChunk> chunkRepository,
            IRepository<Document> documentRepository,
            IAIService aiService)
        {
            _chunkRepository = chunkRepository;
            _documentRepository = documentRepository;
            _aiService = aiService;
        }

        public async Task<List<DocumentSearchResultDto>> SearchSimilarDocumentsAsync(string query, int topK = 5, float threshold = 0.7f)
        {
            try
            {
                // 生成查询向量
                var queryVector = await _aiService.GenerateEmbeddingAsync(query);
                
                // 获取所有文档块
                var allChunks = await _chunkRepository.GetAllAsync();
                
                // 计算相似度并按文档分组
                var documentScores = new Dictionary<Guid, List<(DocumentChunk chunk, float score)>>();
                
                foreach (var chunk in allChunks)
                {
                    if (chunk.Vector == null || chunk.Vector.Length == 0) continue;
                    
                    var similarity = chunk.CosineSimilarity(queryVector);
                    if (similarity >= threshold)
                    {
                        if (!documentScores.ContainsKey(chunk.DocumentId))
                        {
                            documentScores[chunk.DocumentId] = new List<(DocumentChunk, float)>();
                        }
                        documentScores[chunk.DocumentId].Add((chunk, similarity));
                    }
                }

                // 获取相关文档信息
                var documentIds = documentScores.Keys.ToList();
                var documents = await _documentRepository.GetAllAsync();
                var relevantDocuments = documents.Where(d => documentIds.Contains(d.Id)).ToDictionary(d => d.Id);

                var results = new List<DocumentSearchResultDto>();

                foreach (var (docId, chunks) in documentScores)
                {
                    if (!relevantDocuments.ContainsKey(docId)) continue;

                    var document = relevantDocuments[docId];
                    var maxScore = chunks.Max(c => c.score);
                    var avgScore = chunks.Average(c => c.score);
                    var finalScore = (maxScore * 0.7f) + (avgScore * 0.3f); // 加权评分

                    var relevantChunks = chunks
                        .OrderByDescending(c => c.score)
                        .Take(3) // 每个文档最多返回3个最相关的块
                        .Select(c => new DocumentChunkSearchResultDto
                        {
                            ChunkId = c.chunk.Id,
                            DocumentId = c.chunk.DocumentId,
                            Content = c.chunk.Content,
                            ChunkIndex = c.chunk.ChunkIndex,
                            Score = c.score,
                            HighlightedContent = HighlightText(c.chunk.Content, query)
                        })
                        .ToList();

                    results.Add(new DocumentSearchResultDto
                    {
                        DocumentId = docId,
                        Title = document.Name, // 使用Name属性而不是Title
                        Summary = GenerateSummary(relevantChunks.First().Content),
                        Score = finalScore,
                        RelevantChunks = relevantChunks
                    });
                }

                return results.OrderByDescending(r => r.Score).Take(topK).ToList();
            }
            catch (Exception ex)
            {
                throw new Exception($"搜索相似文档时发生错误: {ex.Message}", ex);
            }
        }

        public async Task<List<DocumentChunkSearchResultDto>> SearchSimilarChunksAsync(string query, int topK = 10, float threshold = 0.7f)
        {
            try
            {
                var queryVector = await _aiService.GenerateEmbeddingAsync(query);
                if (queryVector == null || queryVector.Length == 0)
                {
                    Console.WriteLine($"[VectorSearch] 查询向量生成失败");
                    return new List<DocumentChunkSearchResultDto>();
                }

                var allChunks = await _chunkRepository.GetAllAsync();

                var results = new List<DocumentChunkSearchResultDto>();

                Console.WriteLine($"[VectorSearch] 查询: {query}");
                Console.WriteLine($"[VectorSearch] 查询向量长度: {queryVector.Length}");
                Console.WriteLine($"[VectorSearch] 总文档片段数: {allChunks.Count()}");
                Console.WriteLine($"[VectorSearch] 相似度阈值: {threshold}");

                foreach (var chunk in allChunks)
                {
                    if (chunk.Vector == null || chunk.Vector.Length == 0) 
                    {
                        Console.WriteLine($"[VectorSearch] 跳过空向量片段: {chunk.Id}");
                        continue;
                    }

                    var similarity = chunk.CosineSimilarity(queryVector);
                    Console.WriteLine($"[VectorSearch] 片段 {chunk.Id.ToString().Substring(0,8)}...: 相似度={similarity:F4}, 阈值={threshold}, 内容预览='{chunk.Content.Substring(0, Math.Min(50, chunk.Content.Length))}...'");
                    
                    if (similarity >= threshold)
                    {
                        results.Add(new DocumentChunkSearchResultDto
                        {
                            ChunkId = chunk.Id,
                            DocumentId = chunk.DocumentId,
                            Content = chunk.Content,
                            ChunkIndex = chunk.ChunkIndex,
                            Score = similarity,
                            HighlightedContent = HighlightText(chunk.Content, query)
                        });
                        Console.WriteLine($"[VectorSearch] ✓ 添加到结果: 相似度={similarity:F4}");
                    }
                }

                Console.WriteLine($"[VectorSearch] 最终结果数: {results.Count}");
                return results.OrderByDescending(r => r.Score).Take(topK).ToList();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[VectorSearch] 异常: {ex.Message}");
                throw new Exception($"搜索相似文档块时发生错误: {ex.Message}", ex);
            }
        }

        public async Task<bool> IndexDocumentAsync(Guid documentId)
        {
            try
            {
                var document = await _documentRepository.GetByIdAsync(documentId);
                if (document == null)
                {
                    return false;
                }

                // 获取文档的所有块
                var chunks = await _chunkRepository.GetAllAsync();
                var documentChunks = chunks.Where(c => c.DocumentId == documentId).ToList();

                // 为每个块生成向量（如果还没有）
                foreach (var chunk in documentChunks)
                {
                    if (chunk.Vector == null || chunk.Vector.Length == 0)
                    {
                        var embedding = await _aiService.GenerateEmbeddingAsync(chunk.Content);
                        chunk.UpdateVector(embedding);
                        await _chunkRepository.UpdateAsync(chunk);
                    }
                }

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public async Task<bool> RemoveDocumentFromIndexAsync(Guid documentId)
        {
            try
            {
                var chunks = await _chunkRepository.GetAllAsync();
                var documentChunks = chunks.Where(c => c.DocumentId == documentId);
                var chunkIds = documentChunks.Select(c => c.Id);

                await _chunkRepository.DeleteRangeAsync(chunkIds);

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public async Task<bool> RebuildIndexAsync()
        {
            try
            {
                var allDocuments = await _documentRepository.GetAllAsync();
                var successCount = 0;

                foreach (var document in allDocuments)
                {
                    if (await IndexDocumentAsync(document.Id))
                    {
                        successCount++;
                    }
                }

                return successCount == allDocuments.Count();
            }
            catch (Exception)
            {
                return false;
            }
        }

        private string HighlightText(string content, string query)
        {
            // 简单的文本高亮实现
            if (string.IsNullOrEmpty(query)) return content;

            var keywords = query.Split(' ', StringSplitOptions.RemoveEmptyEntries);
            var result = content;

            foreach (var keyword in keywords)
            {
                if (keyword.Length >= 2) // 只高亮长度>=2的关键词
                {
                    result = System.Text.RegularExpressions.Regex.Replace(
                        result, 
                        System.Text.RegularExpressions.Regex.Escape(keyword), 
                        $"<mark>{keyword}</mark>", 
                        System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                }
            }

            return result;
        }

        private string GenerateSummary(string content, int maxLength = 200)
        {
            if (string.IsNullOrEmpty(content)) return string.Empty;
            
            if (content.Length <= maxLength) return content;
            
            var truncated = content.Substring(0, maxLength);
            var lastSpace = truncated.LastIndexOf(' ');
            
            return lastSpace > 0 ? truncated.Substring(0, lastSpace) + "..." : truncated + "...";
        }
    }
}
